/*
 * This program sends periodically packets to an id.
 * To be used in conjunction with recv_one_trigger or recv_two_triggers.
 * Usage:
 * > send_private_id  <cfg_file.xml>
 * > recv_private_trigger <cfg_file.xml>
 *    or 
 * > recv_private_trigger_chain <cfg_file.xml>
 */ 

#include <stdio.h>
#include <sys/time.h>    /* timeval{} for select() */
#include <errno.h>    

#include "i3.h"
#include "i3_client_api.h"
#include "utils.h"

#define TO_SEND_USEC 1000000 
#define TO_SEND_SEC  0

void send_data(ID *id)
{
#define MY_PKT_SIZE 2000
  static long seq = 0;
  long        temp; 
  int         k;
  static cl_buf  *clb = NULL;
  
  if (clb == NULL) 
    clb = cl_alloc_buf(MY_PKT_SIZE);


  temp = htonl(++seq);
  memcpy(clb->data, &temp, sizeof(long));
  clb->data_len = 1000; // sizeof(long); 
  
    /* send packet */
  cl_send(id, clb, 0);
  
  printf("sent, seq. #: %ld\n", seq);
}  

void no_matching_trigger(void *ctx_data, void *data, void *fun_ctx)
{
    ID *id = (ID *) ctx_data;
    
  printf("Following ID not found, ");
  printf_i3_id(id, 0);
}

int i3_main_loop(char *cfg_file)
{
  fd_set      rset;
  int         rc;
  ID          id;
  struct timeval select_to;

  /* initialize context */
  cl_init(cfg_file);

  /* exception when matching trigger not found */
  cl_register_callback(CL_CBK_TRIGGER_NOT_FOUND, no_matching_trigger, NULL);

  /* create packet stack */
  init_id_fromstr(&id, "this is a test id");

  /* the packet's ID should match the prefix of the ID of the receiver's
   * trigger on the length specified the the receiver 
   * (in this case the prefix length is MIN_PREFIX_LEN)
   */
  print_id(&id);

  /** This step is not necessary if you are sure that id is a proper
    * private id, i.e. the public id bit is unset.
    * When you generate an id from a string, it may or may not be private.
    * So you to force it to be private like this.
    */
  cl_set_private_id (&id);
  
  /* setup the timer to send the first packet */
  select_to.tv_usec = TO_SEND_USEC;
  select_to.tv_sec = TO_SEND_SEC;

  /* loop and call cl_select */
  FD_ZERO(&rset);
  for (;;) {

    FD_SET(0, &rset); /* just here, to be modified if application
		       * listens on other fds */
    
    if ((rc = cl_select(0, &rset, NULL, NULL, &select_to)) < 0) {
      if (errno == EINTR)
	continue;
      else
	err_sys("select_error\n");
    }
    
    send_data(&id);
    /* reinitialize the timer */
    select_to.tv_usec = TO_SEND_USEC;
    select_to.tv_sec = TO_SEND_SEC;
  }
  
  /* destroy context */
  cl_exit();
}


int main(int argc, char **argv)
{
  if (argc != 2) {
    printf("%s <cfg_file.xml>\n", argv[0]);
    exit(-1);
  }
  
  i3_main_loop(argv[1]);
  return -1;
}
